/*
 * Copyright (c) 2010, Kelvin Lawson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. No personal names or organizations' names associated with the
 *    Atomthreads project may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE ATOMTHREADS PROJECT AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>

#include "atom.h"
#include "atomtimer.h"
#include "config.h"
#include "console.h"
#include "debug.h"
#include "iosdrv.h"
#include "syslog.h"
#include "shell.h"
#include "devices.h"
#include "packages.h"

/* Constants */

/* Local data */

/* Application threads' TCBs */
static ATOM_TCB main_tcb = DEFAULT_TCB("main");

/* Main thread's stack area */
static uint8_t main_thread_stack[ATOM_MAIN_STACK_SIZE_BYTES];

/* Idle thread's stack area */
static uint8_t idle_thread_stack[ATOM_IDLE_STACK_SIZE_BYTES];

/* Forward declarations */
static void main_thread_func (void* data);

static char logo[] = {
"\r\n\
-------------------------------------------------------- \r\n \
 __   __  _______  _______  ___      _______  \r\n \
|  |_|  ||   _   ||       ||   |    |       | \r\n \
|       ||  |_|  ||    _  ||   |    |    ___| \r\n \
|       ||       ||   |_| ||   |    |   |___  \r\n \
|       ||       ||    ___||   |___ |    ___| \r\n \
| ||_|| ||   _   ||   |    |       ||   |___  \r\n \
|_|   |_||__| |__||___|    |_______||_______| \r\n \
                                              \r\n \
                    powered by yifengling0    \r\n \
                    ver "APP_VERSION"  "__DATE__" "__TIME__"\r\n \
-------------------------------------------------------- \
 \r\n"
};

/**
 * \b main
 *
 * Program entry point.
 *
 * Sets up the AVR hardware resources (system tick timer interrupt) necessary
 * for the OS to be started. Creates an application thread and starts the OS.
 */
extern int board_setup(void);
int main ( void )
{
    uint8_t status;

    /**
     * Brief delay to give the debugger a chance to stop the core before we
     * muck around with the chip's configuration.
     */

    ConsoleInit();
    IosDrvInit();

    board_setup();

    /**
     * Note: to protect OS structures and data during initialisation,
     * interrupts must remain disabled until the first thread
     * has been restored. They are reenabled at the very end of
     * the first thread restore, at which point it is safe for a
     * reschedule to take place.
     */

    DebugPortSetDevice(BSP_DBGPORT_DEVICE_NAME);


    /**
     * Initialise the OS before creating our threads.
     *
     * Note that we cannot enable stack-checking on the idle thread on
     * this platform because we are already using part of the idle
     * thread's stack now as our startup stack. Prefilling for stack
     * checking would overwrite our current stack.
     *
     * If you are not reusing the idle thread's stack during startup then
     * you are free to enable stack-checking here.
     */
    status = atomOSInit(&idle_thread_stack[0], ATOM_IDLE_STACK_SIZE_BYTES, TRUE);
    if (status == ATOM_OK)
    {
        /* Put a message out on the UART */
        KPrint(logo);

        /* Create an application thread */
        status = atomThreadCreate(&main_tcb,
                     16, main_thread_func, 0,
                     &main_thread_stack[0],
                     ATOM_MAIN_STACK_SIZE_BYTES,
                     TRUE);
        if (status == ATOM_OK)
        {
            /**
             * First application thread successfully created. It is
             * now possible to start the OS. Execution will not return
             * from atomOSStart(), which will restore the context of
             * our application thread and start executing it.
             *
             * Note that interrupts are still disabled at this point.
             * They will be enabled as we restore and execute our first
             * thread in archFirstThreadRestore().
             */
            atomOSStart();
        }
    }

    while (1) {
        atomTimerDelay(SYSTEM_TICKS_PER_SEC);
    }


    /* There was an error starting the OS if we reach here */
    return (0);
}


/**
 * \b main_thread_func
 *
 * Entry point for main application thread.
 *
 * This is the first thread that will be executed when the OS is started.
 *
 * @param[in] data Unused (optional thread entry parameter)
 *
 * @return None
 */
static void main_thread_func (void* data)
{
    uint32_t sleep_ticks;

    InitDevices();
    InitPackages();
    ConsoleRun();

    /* Flash LED once per second if passed, very quickly if failed */
    sleep_ticks = 5;

    SYSLOG(LOG_INFO, "System is start %d", sleep_ticks);

    /* Test finished, flash slowly for pass, fast for fail */
    while (1)
    {
        /* Sleep then toggle LED again */
        atomTimerDelay (sleep_ticks);
    }
}
